#ifdef _MANAGED 
#pragma once

//
//  IntrusivePtr.hpp
//
//  Copyright (c) 2014 Stephen Channell
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
//

#include <boost/intrusive_ptr.hpp>

namespace boost
{
	//
	// managed wrapper for a boost intrusive smart pointer for use with C++/CLI
	//
	template<typename T>
	ref class IntrusivePtr
	{
	public:
		IntrusivePtr ()
		{
			reinterpret_cast<boost::intrusive_ptr<T>&>(_fly) = NULL;
		}
		IntrusivePtr (T* fly)
		{
			reinterpret_cast<boost::intrusive_ptr<T>&>(_fly) = fly;
		}

		IntrusivePtr (boost::intrusive_ptr<T>& fly)
		{
			reinterpret_cast<boost::intrusive_ptr<T>&>(_fly) = fly;
		}

		IntrusivePtr (boost::IntrusivePtr<T>^ fly)
		{
			reinterpret_cast<boost::intrusive_ptr<T>&>(_fly) = fly->get();
		}

		IntrusivePtr (boost::IntrusivePtr<T>% fly)
		{
			reinterpret_cast<boost::intrusive_ptr<T>&>(_fly) = fly.get();
		}

		~IntrusivePtr ()
		{
			boost::intrusive_ptr<T> none;
			reinterpret_cast<boost::intrusive_ptr<T>&>(_fly).swap (none);
			System::GC::SuppressFinalize (this);
		}
		!IntrusivePtr ()
		{
			boost::intrusive_ptr<T> none;
			reinterpret_cast<boost::intrusive_ptr<T>&>(_fly).swap (none);
		}

		T* get()  
		{
			return &*(reinterpret_cast<boost::intrusive_ptr<T>&>(_fly));
		}
		void reset ()
		{
			boost::intrusive_ptr<T> none;
			reinterpret_cast<boost::intrusive_ptr<T>&>(_fly).swap (none);
		}

		T* operator-> ()
		{
			return get();
		}
		T& operator= (T* rhs)
		{
			return *((reinterpret_cast<boost::intrusive_ptr<T>&>(_fly)) = rhs);
		}
		T& operator= (boost::intrusive_ptr<T>* rhs)
		{
			return &*((reinterpret_cast<boost::intrusive_ptr<T>&>(_fly)) = rhs);
		}
		T& operator= (boost::intrusive_ptr<T>& rhs)
		{
			return *((reinterpret_cast<boost::intrusive_ptr<T>&>(_fly)) = *&rhs);
		}
		IntrusivePtr<T> operator= (boost::intrusive_ptr<T> rhs)
		{
			return *((reinterpret_cast<boost::intrusive_ptr<T>&>(_fly)) = *&rhs);
		}

		T& operator= (boost::IntrusivePtr<T>^ rhs)
		{
			return *((reinterpret_cast<boost::intrusive_ptr<T>&>(_fly)) = rhs->get());
		}

		T& operator= (boost::IntrusivePtr<T>% rhs)
		{
			return *((reinterpret_cast<boost::intrusive_ptr<T>&>(_fly)) = rhs->get());
		}

		operator boost::intrusive_ptr<T>& ()
		{
			return *((reinterpret_cast<boost::intrusive_ptr<T>&>(_fly)));
		}

		static T& operator* (boost::IntrusivePtr<T>% rhs)
		{
			return *(rhs.get());
		}


	protected:
		System::IntPtr _fly;
	};

	template<class T, class U> inline bool operator==(IntrusivePtr<T> const % a, IntrusivePtr<U> const % b)
	{
		return a.get() == b.get();
	}

	template<class T, class U> inline bool operator!=(IntrusivePtr<T> const % a, IntrusivePtr<U> const % b)
	{
		return a.get() != b.get();
	}

	template<class T, class U> inline bool operator==(intrusive_ptr<T> const & a, IntrusivePtr<U> const % b)
	{
		return a.get() == b.get();
	}

	template<class T, class U> inline bool operator!=(intrusive_ptr<T> const & a, IntrusivePtr<U> const % b)
	{
		return a.get() != b.get();
	}

	template<class T, class U> inline bool operator==(IntrusivePtr<T> const % a, intrusive_ptr<U> const & b)
	{
		return a.get() == b.get();
	}

	template<class T, class U> inline bool operator!=(IntrusivePtr<T> const % a, intrusive_ptr<U> const & b)
	{
		return a.get() != b.get();
	}

	template<class T, class U> inline bool operator==(IntrusivePtr<T> const % a, U * b)
	{
		return a.get() == b;
	}

	template<class T, class U> inline bool operator!=(IntrusivePtr<T> const % a, U * b)
	{
		return a.get() != b;
	}

	template<class T, class U> inline bool operator==(T * a, IntrusivePtr<U> const % b)
	{
		return a == b.get();
	}

	template<class T, class U> inline bool operator!=(T * a, IntrusivePtr<U> const % b)
	{
		return a != b.get();
	}
}
#endif